package DisciplinaTopico;

import DisciplinaTopicoView.TopicoDAO;
import Questao.Dificuldade;
import Questao.Questao;
import Questao.QuestaoDiscursiva;
import Questao.QuestaoMultiplaEscolha;
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class TopicoDAOXML implements TopicoDAO
{
    public static final String XML_TOPICOS = "topicos.xml";

    List<Topico> listaTopicos = new ArrayList<Topico>();

    private List<Topico> criaTopicosIniciais(){

        List<Questao> questoesTopico1 = new ArrayList<Questao>();
        List<Questao> questoesTopico2 = new ArrayList<Questao>();
        List<Questao> questoesTopico3 = new ArrayList<Questao>();
        List<Questao> questoesTopico4 = new ArrayList<Questao>();

        //Topico 1
         String[] respTop1Mult1 = {"360.000", "360", "50.063.860", "50.064.840"};
        Questao probmult1 = new QuestaoMultiplaEscolha("No jogo da Mega-Sena são sorteados, a cada extração, 6 dos números de 1 a 60.Quantos são os resultados possíveis da Mega-Sena?", Dificuldade.Facil, respTop1Mult1, "50.063.860");
        String[] respTop1Mult2 = {"15/16 ", "1/4", "1/16", "3/4"};
        Questao probmult2 = new QuestaoMultiplaEscolha("Um casal decidiu que vai ter 4 filhos. Qual é a probabilidade de que tenham pelo menos um menino?", Dificuldade.Medio, respTop1Mult2, "15/16 ");
        String[] respTop1Mult3 = {"12/24", "11/24", "12/23", "11/23"};
        Questao probmult3 = new QuestaoMultiplaEscolha("24 times são divididos em dois grupos de 12 times cada. Qual é a probabilidade de dois desses times ficarem no mesmo grupo?", Dificuldade.Dificil, respTop1Mult3, "11/23");
        //Questao probdisc1 = new QuestaoDiscursiva("Suponha que se lance um par de dados e que os 36 resultados possíveis são igualmente prováveis. Determine a probabilidade de que a soma dos números observados seja par.", Dificuldade.Facil, "P = 1/2 = 0,5");
        Questao probdisc2 = new QuestaoDiscursiva("Uma comissão de 3 pessoas é formada, escolhendo-se ao acaso entre Antônio, Benedito, César, Denise e Elisabete. Se Denise não pertence à comissão, qual a probabilidade de César pertencer?", Dificuldade.Dificil, "P = 3Combi2 / 4Combi3 =  3/4 = 0,75");
        Questao probdisc3 = new QuestaoDiscursiva("Uma caixa contém 5 bolas brancas e três bolas pretas. Duas bolas são retiradas simultaneamente ao acaso e substituídas por três bolas azuis. Em seguida, duas novas bolas são retiradas ao acaso da caixa. Se as duas últimas bolas retiradas forem uma branca e uma preta, calcular a probabilidade de que, na primeira extração, tenham saído duas bolas brancas. ", Dificuldade.Medio, "P(A / B)=(10/91) / (10/ 28) = 4/13");
        questoesTopico1.add(probmult1);
        questoesTopico1.add(probmult2);
        questoesTopico1.add(probmult3);
        //questoesTopico1.add(probdisc1);
        questoesTopico1.add(probdisc2);
        questoesTopico1.add(probdisc3);

        //Topico 2
        String[] respTop2Mult1 = {"4.8", "35.6", "27.9", "38.4"};
        Questao interConfMult1 = new QuestaoMultiplaEscolha("O intervalo [35.21, 35.99] com confianca 95% foi construído a partir de uma amostra de tamanho 100, para a média de uma populacao normal com desvio padrao igual a 2. Qual o valor encontrado para a media desta amostra?", Dificuldade.Facil, respTop2Mult1, "35.6");
        String[] respTop2Mult2 = {"20.0 +- 0.002", "20.0 +- 0.04", "20.0 +- 0.1", "20.0 +- 0.5"};
        Questao interConfMult2 = new QuestaoMultiplaEscolha("Das arruelas produzidas por uma máquina foi retirada uma amostra de 100 arruelas cujo diâmetro médio é 20,000 mm e desvio padrão 0,012 mm. Determine o intervalo de confiança de 90,50% para o diâmetro médio de todas as arruelas produzidas por esta máquina.", Dificuldade.Medio, respTop2Mult2, "20.0 +- 0.002");
        String[] respTop2Mult3 = {"20.0 +- 0.05", "20.0 +- 0.85", "20.0 +- 1.0", "20.0 +- 0.03"};
        Questao interConfMult3 = new QuestaoMultiplaEscolha("Foram escolhidas 95 medidas de uma peca em um lote muito grande. Sabendo que a medida media obtida foi de 20cm e odesvio padrao de 4cm, calcule o intervalo de confiança de 96% para a medida media do lote.", Dificuldade.Dificil, respTop2Mult3, "20.0 +- 0.85");
        Questao interConfdisc1 = new QuestaoDiscursiva("O tempo médio para um aluno resolver uma determinada prova é de 90 minutos e variância de 36 minutos2. Esses dados foram obtidos a partir de uma amostra com 196 alunos escolhidos de forma aleatória. Construa intervalos de confiança para a verdadeira duração média de realização dessa prova com níveis de confiança de 90%.", Dificuldade.Facil, "90.0 +- 0.704");
        Questao interConfdisc2 = new QuestaoDiscursiva("De 50.000 valvulas fabricadas por uma companhia retira-se uma amostra de 400 valvulas, e obtem a vida media de 800 horas e o desvio padrao de 100 horas. Com que intervalo dir-se-ia que a vida mediae 800 +-0,98?" ,Dificuldade.Dificil, "15,54% de intervalo de confiança.");
        Questao interConfdisc3 = new QuestaoDiscursiva("Em uma central de atendimento, colhida uma amostra aleatória,foram obtidos os seguintes tempos, em minutos, para o atendimento de clientes:13 13 13 14 14 15 15 16 16 Sabendo que a amostra foi extraída de uma população com distribuição normal, construa um intervalo de confiança para o tempo de atendimento médio ao nível de 98%.", Dificuldade.Medio, "14.3 +- 1.182");
        questoesTopico2.add(interConfMult1);
        questoesTopico2.add(interConfMult2);
        questoesTopico2.add(interConfMult3);
        questoesTopico2.add(interConfdisc1);
        questoesTopico2.add(interConfdisc2);
        questoesTopico2.add(interConfdisc3);

        //Topico 3
        String[] respTop3Mult1 = {"0", "1", "2", "4"};
        Questao arvBinMult1 = new QuestaoMultiplaEscolha("Cada nó pode ter até quantas folhas?", Dificuldade.Facil, respTop3Mult1, "2");
        String[] respTop3Mult2 = {"4", "3", "2", "1"};
        Questao arvBinMult2 = new QuestaoMultiplaEscolha("Quantos são os tipos de percursos em árvores?", Dificuldade.Medio, respTop3Mult2, "3");
        String[] respTop3Mult3 = {"algoritmos interligados", "funções paralelas", "recursão", "nenhuma das alternativas acima"};
        Questao arvBinMult3 = new QuestaoMultiplaEscolha("Operacoes em arvores são baseadas em que?", Dificuldade.Dificil, respTop3Mult3, "recursão");
        Questao arvBindisc1 = new QuestaoDiscursiva("Arvore binaria é uma estrutura de dados? (sim/não)", Dificuldade.Facil, "sim");
        Questao arvBindisc2 = new QuestaoDiscursiva("O que significa uma Uma árvore estritamente binária?", Dificuldade.Dificil,"É uma árvore na qual todo nó tem zero ou dois filhos");
        Questao arvBindisc3 = new QuestaoDiscursiva("O que significa a profundidade de um nó ?", Dificuldade.Medio, "é a distância deste nó até a raiz");
        questoesTopico3.add(arvBinMult1);
        questoesTopico3.add(arvBinMult2);
        questoesTopico3.add(arvBinMult3);
        questoesTopico3.add(arvBindisc1);
        questoesTopico3.add(arvBindisc2);
        questoesTopico3.add(arvBindisc3);

        //Topico 4
         String[] respTop4Mult1 = {"é o grafo com conjunto de vértices vazio", "é o grafo com conjunto de arestas vazio", "é o grafo sem loops", "nenhuma das alternativas acima"};
        Questao grafoDirecMult1 = new QuestaoMultiplaEscolha("O qeu é grafo nulo?", Dificuldade.Facil, respTop4Mult1, "é o grafo com conjunto de vértices vazio.");
        String[] respTop4Mult2 = {"dois", "um", "quatro", "n"};
        Questao grafoDirecMult2 = new QuestaoMultiplaEscolha("Uma aresta conecta quantos vertices?", Dificuldade.Medio, respTop4Mult2, "dois");
        String[] respTop4Mult3 = {"é um grafo que contém arestas apenas arestas simples, sem paralelo", "é um grafo que contém arestas paralelas e laços", "é um grafo não contém arestas paralelas e laços", "é um grafo que contém apenas arestas, sem laços"};
        Questao grafoDirecMult3 = new QuestaoMultiplaEscolha("O que é um pseudografo?", Dificuldade.Dificil, respTop4Mult3, "é um grafo que contém arestas paralelas e laços");
        Questao grafoDirecdisc1 = new QuestaoDiscursiva("O que é grafo vazio?", Dificuldade.Facil, "é o grafo cujo conjunto de arestas é vazio.");
        Questao grafoDirecdisc2 = new QuestaoDiscursiva("O que é multigrafo?", Dificuldade.Dificil, "é um grafo que permite múltiplas arestas ligando os mesmos vértices (arestas paralelas).");
        Questao grafoDirecdisc3 = new QuestaoDiscursiva("O que é grafo trivial?", Dificuldade.Medio, "É um grafo com um único vértice e sem arestas ");
        questoesTopico4.add(grafoDirecMult1);
        questoesTopico4.add(grafoDirecMult2);
        questoesTopico4.add(grafoDirecMult3);
        questoesTopico4.add(grafoDirecdisc1);
        questoesTopico4.add(grafoDirecdisc2);
        questoesTopico4.add(grafoDirecdisc3);


        Topico t1 = new Topico("Probabilidade Condicional", questoesTopico1);
        listaTopicos.add(t1);

        Topico t2 = new Topico("Intervalo de Confiança", questoesTopico2);
        listaTopicos.add(t2);

        Topico t3 = new Topico("Árvore Binária de Busca", questoesTopico3);
        listaTopicos.add(t3);

        Topico t4 = new Topico("Algoritmos para Grafos Direcionais", questoesTopico4);
        listaTopicos.add(t4);

        return listaTopicos;
    }

     public TopicoDAOXML() throws TopicoDAOException
    {
        readTopicos();
    }

    private void readTopicos() throws TopicoDAOException
    {
        readTopicos(XML_TOPICOS);
    }

    private void readTopicos(String nomeArquivo) throws TopicoDAOException
    {
         XMLDecoder informacoesArquivo = null;

        try
        {
            File inputFile = new File(nomeArquivo);
            if(inputFile.exists())
            {
                try
                {
                    informacoesArquivo = new XMLDecoder(new FileInputStream(nomeArquivo));
                    listaTopicos = (List<Topico>)informacoesArquivo.readObject();
                }
                finally
                {
                    if(informacoesArquivo != null)
                        informacoesArquivo.close();
                }
            }
            else
            {
                listaTopicos = criaTopicosIniciais();
                writeTopicos();
            }
        }
        catch(IOException exception)
        {
            TopicoDAOException topicoDAOException = new TopicoDAOException("ERRO: Não foi possível ler os dados do arquivo '" + nomeArquivo + "'.");

            topicoDAOException.setStackTrace(exception.getStackTrace());

            throw topicoDAOException;
        }
    }

     private void writeTopicos()throws TopicoDAOException
    {
        writeTopicos(XML_TOPICOS);
    }

    private void writeTopicos(String nomeArquivo) throws TopicoDAOException
    {
        XMLEncoder informacoesArquivo = null;

        try
        {
            try
            {
                informacoesArquivo = new XMLEncoder(new FileOutputStream(nomeArquivo));
                informacoesArquivo.writeObject(listaTopicos);
            }
            finally
            {
                if(informacoesArquivo != null)
                    informacoesArquivo.close();
            }
        }
        catch(IOException exception)
        {
            TopicoDAOException topicoDAOXMLException = new TopicoDAOException("ERRO: Não foi possível escrever todos os dados no arquivo '" + nomeArquivo + "'.");

            topicoDAOXMLException.setStackTrace(exception.getStackTrace());

            throw topicoDAOXMLException;
        }
    }

    public List<Topico> getTopicos() throws TopicoDAOException
    {
        return listaTopicos;
    }

    private boolean contemTopico(Topico outroTopico)
    {
        for(Topico t : listaTopicos)
            if(t.equals(outroTopico))
                return true;

        return false;
    }

    private boolean contemQuestao(Topico topico, Questao questao)
    {
        List<Questao> listaQuestoes = topico.getQuestoes();

        for(Questao q : listaQuestoes)
            if(q.equals(questao))
                return true;

        return false;
    }

     private int getNumQuestoes(Topico topico)
    {
        if(topico != null)
            return topico.getQuestoes().size();
        else
            return 0;
    }

     public void adiconarQuestao(Topico topico, Questao novaQuestao) throws QuestaoDAOException, TopicoDAOException
    {
        if(contemQuestao(topico,novaQuestao))
            throw new QuestaoDAOException("ERRO: Questao já esta cadastrada no sistema.");
        else
        {
            List<Questao> novaListaQuestoes = topico.getQuestoes();
            novaListaQuestoes.add(novaQuestao);
            topico.setQuestoes(novaListaQuestoes);
            
            writeTopicos();
        }
    }

    @SuppressWarnings("ResultOfObjectAllocationIgnored")
    public void editarQuestao(Topico topicoAlterado, Questao questaoAlterada) throws QuestaoDAOException
    {
        if(questaoAlterada == null)
            throw new QuestaoDAOException("ERRO: A questao a ser alterada não é válida.");

        Questao questaoAntiga = null;
        List<Questao> listaQuestoes = topicoAlterado.getQuestoes();

        for(Questao q : listaQuestoes)
        {
            if(q.getID().equals(questaoAlterada.getID()))
                questaoAntiga = q;
        }

        if(questaoAntiga != null)
        {
            try 
            {
                listaQuestoes.remove(questaoAntiga);
                listaQuestoes.add(questaoAlterada);
                topicoAlterado.setQuestoes(listaQuestoes);

                writeTopicos();
            }
            catch (TopicoDAOException ex)
            {
                //new QuestaoDAOException(ex.getMessage());
            }
        }
        else
            throw new QuestaoDAOException("ERRO: A questao a ser alterada não esta cadastrada no banco ou não pertencea este tópico.");
    }

    public void excluirQuestao(Topico topico, Questao questaoExcluida) throws QuestaoDAOException, TopicoDAOException
    {
         if(!contemQuestao(topico,questaoExcluida))
            throw new QuestaoDAOException("ERRO: A questão a ser excluida não esta cadastrada no banco ou não pertence a este tópico.");

         else
         {
            List<Questao> novaListaQuestoes = topico.getQuestoes();
            novaListaQuestoes.remove(questaoExcluida);
            topico.setQuestoes(novaListaQuestoes);

            writeTopicos();
         }
    }

    public Topico obterTopicoQuestao(Questao questaoRelacionada)
    {
        Topico topicoRelacionado = null;
        
        for(Topico topico : listaTopicos)
            if(topico.getQuestoes().contains(questaoRelacionada))
                topicoRelacionado = topico;
        
        return topicoRelacionado;
    }
}
